<template>
  <view :class="ns.b()">
    <IBizView
      v-if="isLoaded && hasAuthority"
      v-bind="$attrs"
      :key="key"
      :params="params"
      :context="context"
      :modelData="viewModel"
      :provider="provider"
      @redrawView="handleRedrawView"
    ></IBizView>
    <view v-else-if="!hasAuthority">403</view>
  </view>
</template>

<script setup lang="ts">
import { createUUID } from 'qx-util'
import { IAppView } from '@ibiz/model-core'
import { isEmpty, isNil } from 'ramda'
import { RuntimeError } from '@ibiz-template/core'
import {
  getViewProvider,
  IViewProvider,
  calcDynaSysParams,
  RedrawViewEvent,
} from '@ibiz-template/runtime'
import { useUserStore } from '@/store'
import { useNamespace } from '@/use'

const props = defineProps({
  context: { type: Object as PropType<IContext>, required: true },
  params: { type: Object as PropType<IParams> },
  modelData: { type: Object as PropType<IAppView> },
  viewId: { type: String },
})

const ns = useNamespace('view-shell')
const isLoaded: Ref<boolean> = ref(false)
const key: Ref<string> = ref(createUUID())
const errMsg: Ref<string> = ref('')
const provider: Ref<IViewProvider | undefined> = ref<IViewProvider>()
// 视图模型
const viewModel: Ref<IAppView | undefined> = ref<IAppView | undefined>()
// 权限
const hasAuthority: Ref<boolean> = ref(true)
// 当前视图上下文
const context: Ref<IContext> = ref(props.context)
// 当前视图参数
const params: Ref<IParams> = ref(props.params || {})

watch(
  () => ({ context: props.context, params: props.params }),
  (newVal) => {
    context.value = newVal.context
    params.value = newVal.params ? newVal.params : {}
  },
)

/**
 * 初始化视图模型
 */
const initViewModel = async (): Promise<IAppView> => {
  return props.modelData ? props.modelData : await ibiz.hub.getAppView(props.viewId)
}

/**
 * 检查视图权限
 */
const checkViewAuthority = async (viewModel: IAppView): Promise<boolean> => {
  let checkResult: boolean = true
  const { accUserMode, accessKey } = viewModel
  // TODO 获取登录信息
  const authInfo = useUserStore().userInfo
  // 0：未指定、 1：未登录用户、 2：登录用户、 3：未登录用户及登录用户、 4：登录用户且拥有指定资源能力
  if (accUserMode !== undefined) {
    switch (accUserMode) {
      case 1:
        if (authInfo) {
          checkResult = false
        }
        break
      case 2:
        if (!authInfo) {
          checkResult = false
        }
        break
      case 4:
        if (accessKey) {
          const app = await ibiz.hub.getApp(context.value.srfappid)
          const permitted = app.authority.calcByResCode(accessKey)
          if (!permitted) {
            checkResult = false
          }
        }
        break
      default:
        break
    }
  }
  return checkResult
}

/**
 * 计算视图模型
 */
const calcViewModel = async () => {
  const _viewModel = await initViewModel()
  if (!_viewModel) {
    throw new RuntimeError(ibiz.i18n.t('vue3Util.common.noFoundViewModel'))
  }
  // 检查权限
  hasAuthority.value = await checkViewAuthority(_viewModel)
  if (hasAuthority.value) {
    if (_viewModel.dynaSysMode === 1) {
      //* 计算实体资源路径上下文参数
      const appDataEntityId = _viewModel.appDataEntityId
      if (!appDataEntityId) {
        throw new RuntimeError(
          ibiz.i18n.t('vue3Util.common.noSupportLoadingDynamic', {
            codeName: _viewModel.codeName,
          }),
        )
      }

      /** 加载动态模型的请求参数 */
      const loadModelParams: IParams = await calcDynaSysParams(appDataEntityId, context.value, {
        viewParams: params,
        appId: _viewModel.appId,
      })

      if (params.value.srfdatatype) {
        loadModelParams.srfdatatype = params.value.srfdatatype
      }

      // 如果视图参数中存在 srfwftag 则直接使用视图参数
      if (params.value.srfwftag) {
        loadModelParams.srfwftag = params.value.srfwftag
      } else if (appDataEntityId && _viewModel.enableWF) {
        // 处理数据请求的上下文
        // 存在主键则加载数据计算对应的参数
        if (loadModelParams.srfkey) {
          const noSrfSessionId =
            isNil(context.value.srfsessionid) || isEmpty(context.value.srfsessionid)
          const id = createUUID()
          // 只要上下文中无 srfsessionid 则生成一个
          if (noSrfSessionId) {
            // 生成一个界面域，界面域标识为当前控制器实例的标识
            const domain = ibiz.uiDomainManager.create(id)
            context.value.srfsessionid = domain.id
          }

          const app = ibiz.hub.getApp(_viewModel.appId)
          const service = await app.deService.getService(context.value, appDataEntityId!)
          const res = await service.get(context.value, params.value || {})
          if (res.ok && res.data) {
            const { srfwftag, processdefinitionkey, taskdefinitionkey } = res.data
            if (srfwftag) {
              loadModelParams.srfwftag = srfwftag
            }

            // *动态工作流编辑视图从数据里额外获取参数
            if (['DEWFDYNAEDITVIEW3', 'DEWFDYNAEDITVIEW'].includes(_viewModel.viewType!)) {
              // 如果视图参数中没有获取到对应流程实例标识与步骤标识，则从请求回来的数据中获取对应信息
              if (isNil(params.value.processDefinitionKey)) {
                params.value.processDefinitionKey = processdefinitionkey
              }
              if (isNil(params.value.taskDefinitionKey)) {
                params.value.taskDefinitionKey = taskdefinitionkey
              }
            }
          }

          if (noSrfSessionId) {
            ibiz.uiDomainManager.destroy(id)
          }
        }
      }

      // *加载动态模型
      viewModel.value = await ibiz.hub.loadAppView(
        _viewModel.appId,
        _viewModel.id!,
        loadModelParams,
      )
    } else {
      viewModel.value = _viewModel
    }

    try {
      provider.value = await getViewProvider(_viewModel)
    } catch (error) {
      errMsg.value = error.message
    } finally {
      isLoaded.value = true
    }
  }
}

/**
 * 处理视图重绘
 */
const handleRedrawView = async (event: RedrawViewEvent): Promise<void> => {
  const { redrawData } = event
  const { isReloadModel } = redrawData
  // 合并参数
  Object.assign(context.value, redrawData.context)
  Object.assign(params.value, redrawData.params)
  if (isReloadModel) {
    await calcViewModel()
  }
  key.value = createUUID()
}

onMounted(() => {
  calcViewModel()
})
</script>
